#ifndef NATIVETYPES_H
#define NATIVETYPES_H

#include "primitives.h"

#include <map>
#include <list>
#include <string>
#include <vector>

#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/pop_back.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/any.hpp>
#include <boost/function.hpp>


namespace awa {
  
  
#define GENERATETYPE(r, index)						\
  ((BOOST_PP_SEQ_ELEM( BOOST_PP_DEC(index), AWAENUMTYPE))		\
   (BOOST_PP_SEQ_ELEM( BOOST_PP_DEC(index), AWATYPESYMBOL))		\
   (BOOST_PP_SEQ_ELEM( BOOST_PP_DEC(index), AWATYPEMAP))		\
   (BOOST_PP_SEQ_ELEM( BOOST_PP_DEC(index), AWATYPEFORMATFN)))
  
  
#define DECREASE_NB_BY_ONE(r, number)  BOOST_PP_SUB(number, 1)
  
#define IF_NOT_ZERO(r, number)  number
  
  
#define NB_OF_PRIMITIVES  BOOST_PP_SEQ_SIZE( AWAENUMTYPE )
  
#define ELIGIBLE_TYPES				\
  BOOST_PP_FOR(NB_OF_PRIMITIVES,		\
	       IF_NOT_ZERO,			\
	       DECREASE_NB_BY_ONE,		\
	       GENERATETYPE) 
  
  
  
  
  enum TypeEnum {
    BOOST_PP_SEQ_ENUM(AWAENUMTYPE)
  } ; 
  
  
  // typedef boost::function<Generic()>     PUSH;
  
  typedef boost::any                           Generic;
  
  struct Impl;
  typedef std::string                           InputSrc;
  typedef InputSrc                              Interface;
  
  typedef std::list<Interface>                  Signature;
  
  typedef std::map<Signature, Impl>             ImplCollection;
  
  typedef std::map<Interface, ImplCollection>   ObjectCollection;
  
  typedef std::map<Interface, ObjectCollection>  TypeCollection;
  
  struct Impl {
    typedef std::vector<Generic> FnArgs;
    typedef void*            Callback;
    
  Impl(const Impl& i) : fn(i.fn), args(i.args) {}
    
  Impl(const Callback& f, const FnArgs& a = FnArgs() ) : fn(f), args(a) {}
  Impl() : fn(NULL) {}
    ~Impl()
    {
      // TODO: To avoid warning msg
      //delete fn;
    }
    Impl& operator = ( const Impl& i )
    {
      fn = i.fn;
      args = i.args;
    }
      Callback fn;
    FnArgs args; 
  };
  
  typedef Impl    Function;
  
  TypeCollection  NativeTypes;
  
#define FETCHPARAM(z, n, data) data
#define ENUM(n, param)				\
  BOOST_PP_ENUM(n, FETCHPARAM, param)
#define FNPOINTER(n)							\
  BOOST_PP_CAT(boost::function, BOOST_PP_INC(n))<Generic, AwaAbstract* BOOST_PP_COMMA_IF(n) ENUM(n, Generic)>
  
#define NEWTYPE(n)     BOOST_PP_CAT(F, n)
  
#define FNDEF(z, n, data )			\
  typedef FNPOINTER(n) NEWTYPE(n);
  
#define TYPEDEF					\
  BOOST_PP_REPEAT(MAX_ARG, FNDEF, ~)
  
  struct AwaAbstract {
    
    TYPEDEF
    
    virtual Generic EXEC( const Function& ) = 0;
    
  };
 
  template<class T>
    T castTo(const Generic&);


  extern std::pair<Signature, Impl> MainEntry;
};

#endif
